/* FCE Ultra - NES/Famicom Emulator
 *
 * Copyright notice for this file:
 *  Copyright (C) 2002 Ben Parnell
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

//TYPES
typedef unsigned char		_u8;
typedef unsigned short		_u16;
typedef unsigned int		_u32;
typedef	signed char			_s8;
typedef signed short		_s16;
typedef signed int			_s32;

//BOOL
typedef int					BOOL;
#define TRUE				1
#define FALSE				0



#include <windows.h>
#include <stdio.h>
#include "win_cheat.h"
//#include "font.h"
#include "cheat.h"

static HWND acwin=0;

static int selcheat;
static int scheatmethod=0;
static _u8 cheatval1=0;
static _u8 cheatval2=0;

HINSTANCE gui_hInstance = NULL;


static void winCenterWindow(HWND window)
{
	int x,y;
  RECT parentRect;
  RECT rect;
  HWND parent = GetParent(window);

  if(parent == NULL)
    parent = GetDesktopWindow();

  GetWindowRect(parent, &parentRect);
  GetWindowRect(window, &rect);

  x = parentRect.left + (parentRect.right - parentRect.left -
                         rect.right + rect.left) / 2;
  y = parentRect.top + (parentRect.bottom - parentRect.top -
                        rect.bottom + rect.top) / 2;

  if(x < 0)
    x = 0;
  if(y < 0)
    y = 0;
  
  SetWindowPos(window, NULL, x, y, -1, -1,
               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);  
}


static _u32 StrToU32(char *s)
{
 unsigned int ret=0;
 sscanf(s,"%x",&ret);
 return ret;
}

static _u32 StrToU32D(char *s)
{
 unsigned int ret=0;
 sscanf(s,"%d",&ret);
 return ret;
}

static _u16 StrToU16(char *s)
{
 unsigned int ret=0;
 sscanf(s,"%4x",&ret);
 return ret;
}

static _u8 StrToU8(char *s)
{
 unsigned int ret=0;
 sscanf(s,"%d",&ret);
 return ret;
}


/* Need to be careful where these functions are used. */
static char *U32ToStr(_u32 a)
{
 static char TempArray[32];
 sprintf(TempArray,"%08X",a);
 return TempArray;
}

static char *U16ToStr(_u16 a)
{
 static char TempArray[32];
 sprintf(TempArray,"%04X",a);
 return TempArray;
}

static char *U8ToStr(_u8 a)
{
 static char TempArray[32];
 sprintf(TempArray,"%03d",a);
 return TempArray;
}


//===========================================================

static void DecimalBytes (_u32 value, char* string)
{
	char ValueStr[2048];

	// take off a byte
	sprintf (string, "%d\0", value % 256);
	value /= 256;
	
	while (value > 0) {
		strcpy (ValueStr, string);
		sprintf (string, "%d, %s", value % 256, ValueStr);
		value /= 256;
	}
}

BOOL CALLBACK CalculatorConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	char TempArray[256];
	_u32 t;

  switch(uMsg)
  {
   case WM_INITDIALOG:                  
		winCenterWindow(hwndDlg);
		break;
   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
		if(!(wParam>>16))
			switch(wParam&0xFFFF)
      {
				// convert value to bytes
				case 1002:
					GetDlgItemText(hwndDlg,1000,TempArray,256);
					t=StrToU32D(TempArray);
					DecimalBytes(t,TempArray);
					SetDlgItemText(hwndDlg,1001,TempArray);
					break;

				// close down calculator
 				case 1:
				gornk:
					EndDialog(hwndDlg,0);
				break;
			}
		break;
	}

	return 0;
}


static void CalculatorCheats(HWND hParent)
{
 DialogBox(gui_hInstance,"CALCULATOR",hParent,CalculatorConCallB);
}

//===========================================================

BOOL CALLBACK DrawSpritesCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	char TempArray[256];
	_u32 t;

  switch(uMsg)
  {
   case WM_INITDIALOG:                  
		winCenterWindow(hwndDlg);
		break;
   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
		if(!(wParam>>16))
			switch(wParam&0xFFFF)
      {
				// close down box
				case 1:
 				case 3:
				gornk:
					// convert values to bytes
					//GetDlgItemText(hwndDlg,1000,TempArray,256);
					//sprite_range1=StrToU32(TempArray);

					//GetDlgItemText(hwndDlg,1001,TempArray,256);
					//sprite_range2=StrToU32(TempArray);

					EndDialog(hwndDlg,0);
					break;
			}
		break;
	}

	return 0;
}


void DrawSpritesBox(HWND hParent)
{
 DialogBox(gui_hInstance,"DRAW_SPRITE",hParent,DrawSpritesCallB);
}

//===========================================================


static HWND RedoCheatsWND;
static int RedoCheatsCallB(char *name, _u32 a, _u8 v, int s)
{
 SendDlgItemMessage(RedoCheatsWND,101,LB_ADDSTRING,0,(LPARAM)(LPSTR)name);
 return(1);
}

static void RedoCheatsLB(HWND hwndDlg)
{
 SendDlgItemMessage(hwndDlg,101,LB_RESETCONTENT,0,0);
 RedoCheatsWND=hwndDlg;
 ListCheats(RedoCheatsCallB);
}


BOOL CALLBACK CheatsConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch(uMsg)
  {
   case WM_INITDIALOG:                  
								winCenterWindow(hwndDlg);
                RedoCheatsLB(hwndDlg);
                break;
   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
                switch(HIWORD(wParam))
                {
                 case BN_CLICKED:
                        if(selcheat>=0)
                        {
                         if(LOWORD(wParam)==107)
                          SetCheat(selcheat,0,-1,-1,1);
                         else if(LOWORD(wParam)==108)
                          SetCheat(selcheat,0,-1,-1,0);
                        }
                        break;
                 case EN_KILLFOCUS:
                        if(selcheat>=0)
                        {
                         char TempArray[256];
                         int t;

                         GetDlgItemText(hwndDlg,LOWORD(wParam),TempArray,256);
                         switch(LOWORD(wParam))
                         {
                          case 102:SetCheat(selcheat,TempArray,-1,-1,-1);
                                   SendDlgItemMessage(hwndDlg,101,LB_INSERTSTRING,selcheat,(LPARAM)(LPCTSTR)TempArray);
                                   SendDlgItemMessage(hwndDlg,101,LB_DELETESTRING,selcheat+1,0);
                                   SendDlgItemMessage(hwndDlg,101,LB_SETCURSEL,selcheat,0);
                                   break;
                          case 103:t=StrToU16(TempArray);
                                   SetCheat(selcheat,0,t,-1,-1);
                                   break;
                          case 104:t=StrToU8(TempArray);
                                   SetCheat(selcheat,0,-1,t,-1);
                                   break;
                         }
                        }
                        break;
                }

                switch(LOWORD(wParam))
                {
                 case 101:
                        if(HIWORD(wParam)==LBN_SELCHANGE)
                        {
                         char *s;
                         _u32 a;
                         _u8 b;
												 int status;

                         selcheat=SendDlgItemMessage(hwndDlg,101,LB_GETCURSEL,0,(LPARAM)(LPSTR)0);
                         if(selcheat<0) break;

                         GetCheat(selcheat,&s,&a,&b,&status);
                         SetDlgItemText(hwndDlg,102,(LPTSTR)s);
                         SetDlgItemText(hwndDlg,103,(LPTSTR)U32ToStr(a));
                         SetDlgItemText(hwndDlg,104,(LPTSTR)U8ToStr(b));

                         CheckRadioButton(hwndDlg,107,108,status?107:108);
                        }
                        break;
                }

                if(!(wParam>>16))
                switch(wParam&0xFFFF)
                {
                 case 106:
                          if(selcheat>=0)
                          {
                           DelCheat(selcheat);
                           SendDlgItemMessage(hwndDlg,101,LB_DELETESTRING,selcheat,0);
                           selcheat=-1;
                           SetDlgItemText(hwndDlg,102,(LPTSTR)"");
                           SetDlgItemText(hwndDlg,103,(LPTSTR)"");
                           SetDlgItemText(hwndDlg,104,(LPTSTR)"");
                           CheckRadioButton(hwndDlg,107,108,0); // Is this correct?
                          }
                          break;
                 case 105:
                          ConfigAddCheat(hwndDlg);
                          RedoCheatsLB(hwndDlg);
                          break;
								 case 1000:
									 CalculatorCheats (hwndDlg);
									 break;
                 case 1:
                        gornk:
                        EndDialog(hwndDlg,0);
                        break;
                }
              }
  return 0;
}


void ConfigCheats(HWND hParent)
{
	HWND hwnd;

	/*
	hParent = CreateWindowEx(0, "Cheat", "Cheat",
		WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
		0,	0,	10, 10,
		NULL, NULL, g_hInstance, NULL);
	*/

	// if(!rom.data)
 {
  //DispMessage("You must have a game loaded before you can manipulate cheats.");
  //return;
 }

 selcheat=-1;

 DialogBox(gui_hInstance,"CHEATS",NULL,CheatsConCallB);
 //MessageBox( NULL, "OK", "OK", MB_OK );
}






int cfcallb(_u32 a, _u8 last, _u8 current)
{
 char temp[32];

 sprintf(temp,"%06X:%03d:%03d",(unsigned int)a,last,current);
 SendDlgItemMessage(acwin,108,LB_ADDSTRING,0,(LPARAM)(LPSTR)temp);
 return(1);
}

static int scrollindex;
static int scrollnum;
static int scrollmax;

int cfcallbinsert(_u32 a, _u8 last, _u8 current)
{
 char temp[32];

 sprintf(temp,"%06X:%03d:%03d",(unsigned int)a,last,current);
 SendDlgItemMessage(acwin,108,LB_INSERTSTRING,15,(LPARAM)(LPSTR)temp);
 return(1);
}

int cfcallbinsertt(_u32 a, _u8 last, _u8 current)
{
 char temp[32];

 sprintf(temp,"%06X:%03d:%03d",(unsigned int)a,last,current);
 SendDlgItemMessage(acwin,108,LB_INSERTSTRING,0,(LPARAM)(LPSTR)temp);
 return(1);
}


void AddTheThing(HWND hwndDlg, char *s, int a, int v)
{
 if(AddCheat(s,a,v))
  MessageBox(hwndDlg,"Cheat Added","Cheat Added",MB_OK);
}


static void DoGet(void)
{
 int n=CheatSearchGetCount();
 int t;
 scrollnum=n;
 scrollindex=-32768;

 SendDlgItemMessage(acwin,108,LB_RESETCONTENT,0,0);
 CheatSearchGetRange(0,15,cfcallb);

 t=-32768+n-1-15;
 if(t<-32768)
  t=-32768;
 scrollmax=t;
 SendDlgItemMessage(acwin,120,SBM_SETRANGE,-32768,t);
 SendDlgItemMessage(acwin,120,SBM_SETPOS,-32768,1);
}

static BOOL CALLBACK AddCheatCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  static int lbfocus;
  static HWND hwndLB;

  switch(uMsg)
  {                                                                               
   case WM_VSCROLL:
                if(scrollnum>15)
                {
                 switch((int)LOWORD(wParam))
                 {
                  case SB_TOP:
                        scrollindex=-32768;
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,15,0);
                        CheatSearchGetRange(scrollindex+32768,scrollindex+32768+15,cfcallb);
                        break;
                  case SB_BOTTOM:
                        scrollindex=scrollmax;
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,15,0);
                        CheatSearchGetRange(scrollindex+32768,scrollindex+32768+15,cfcallb);
                        break;
                  case SB_LINEUP:
                        if(scrollindex>-32768)
                        {
                         scrollindex--;
                         SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                         SendDlgItemMessage(hwndDlg,108,LB_DELETESTRING,15,0);
                         CheatSearchGetRange(scrollindex+32768,scrollindex+32768,cfcallbinsertt);
                        }
                        break;

                  case SB_PAGEUP:
                        scrollindex-=16;
                        if(scrollindex<-32768) scrollindex=-32768;
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,15,0);
                        CheatSearchGetRange(scrollindex+32768,scrollindex+32768+15,cfcallb);
                        break;

                  case SB_LINEDOWN:
                        if(scrollindex<scrollmax)
                        {
                         scrollindex++;
                         SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                         SendDlgItemMessage(hwndDlg,108,LB_DELETESTRING,0,0);
                         CheatSearchGetRange(scrollindex+32768+15,scrollindex+32768+15,cfcallbinsert);
                        }
                        break;

                  case SB_PAGEDOWN:
                        scrollindex+=16;
                        if(scrollindex>scrollmax)
                         scrollindex=scrollmax;
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,0,0);
                        CheatSearchGetRange(scrollindex+32768,scrollindex+32768+15,cfcallb);
                        break;

                  case SB_THUMBPOSITION:
                  case SB_THUMBTRACK:
                        scrollindex=(short int)HIWORD(wParam);
                        SendDlgItemMessage(hwndDlg,120,SBM_SETPOS,scrollindex,1);
                        SendDlgItemMessage(hwndDlg,108,LB_RESETCONTENT,0,0);
                        CheatSearchGetRange(32768+scrollindex,32768+scrollindex+15,cfcallb);
                        break;
                 }

                }                
                break;

   case WM_INITDIALOG:
								winCenterWindow(hwndDlg);
                acwin=hwndDlg;
                SetDlgItemText(hwndDlg,110,(LPTSTR)U8ToStr(cheatval1));
                SetDlgItemText(hwndDlg,111,(LPTSTR)U8ToStr(cheatval2));
                DoGet();
                CheckRadioButton(hwndDlg,115,120,scheatmethod+115);
                lbfocus=0;
                hwndLB=0;
                break;

   case WM_VKEYTOITEM:
                if(lbfocus)
                {
                 int real;

                 real=SendDlgItemMessage(hwndDlg,108,LB_GETCURSEL,0,(LPARAM)(LPSTR)0);
                 switch((int)LOWORD(wParam))
                 {
                  case VK_UP: 
                              /* mmmm....recursive goodness */
                              if(!real)
                               SendMessage(hwndDlg,WM_VSCROLL,SB_LINEUP,0);
                              return(-1);
                              break;
                  case VK_DOWN:
                              if(real==15)
                               SendMessage(hwndDlg,WM_VSCROLL,SB_LINEDOWN,0);
                              return(-1);
                              break;
                  case VK_PRIOR:
                              SendMessage(hwndDlg,WM_VSCROLL,SB_PAGEUP,0);
                              break;
                  case VK_NEXT:
                              SendMessage(hwndDlg,WM_VSCROLL,SB_PAGEDOWN,0);
                              break;
                  case VK_HOME:
                              SendMessage(hwndDlg,WM_VSCROLL,SB_TOP,0);
                              break;
                  case VK_END:
                              SendMessage(hwndDlg,WM_VSCROLL,SB_BOTTOM,0);
                              break;
                 }
                 return(-2);
                }
                break;

   case WM_CLOSE:
   case WM_QUIT: goto gornk;
   case WM_COMMAND:
                switch(LOWORD(wParam))
                {
                 case 108:
                        switch(HIWORD(wParam))
                        {
                         case LBN_SELCHANGE:
                                 {
                                  char TempArray[32];
                                  SendDlgItemMessage(hwndDlg,108,LB_GETTEXT,SendDlgItemMessage(hwndDlg,108,LB_GETCURSEL,0,(LPARAM)(LPSTR)0),(LPARAM)(LPCTSTR)TempArray);
                                  TempArray[6]=0;
                                  SetDlgItemText(hwndDlg,201,(LPTSTR)TempArray);                                 
                                 }
                                 break;
                         case LBN_SETFOCUS:
                                 lbfocus=1;
                                 break;
                         case LBN_KILLFOCUS:
                                 lbfocus=0;
                                 break;
                        }
                        break;
                }

                switch(HIWORD(wParam))
                {
                 case BN_CLICKED:
                        if(LOWORD(wParam)>=115 && LOWORD(wParam)<=124)
												{
												 if(wParam>=120) wParam--;
                         scheatmethod=LOWORD(wParam)-115;
												}
                        break;
                 case EN_CHANGE:
                        {
                         char TempArray[256];
                         GetDlgItemText(hwndDlg,LOWORD(wParam),TempArray,256);
                         switch(LOWORD(wParam))
                         {
                          case 110:cheatval1=StrToU8(TempArray);break;
                          case 111:cheatval2=StrToU8(TempArray);break;
                         }
                        }
                        break;
                }


                if(!(wParam>>16))
                switch(wParam&0xFFFF)
                {
                 case 112:
                          CheatSearchBegin();
                          DoGet();
                          break;
                 case 113:
                          CheatSearchEnd(scheatmethod,cheatval1,cheatval2);
                          DoGet();
                          break;
                 case 114:
                          CheatSearchSetCurrentAsOriginal();
                          DoGet();
                          break;
                 case 107:
                          CheatSearchShowExcluded();
                          DoGet();
                          break;
                 case 105:
                          {
                           int a,v;
                           char temp[256];

                           GetDlgItemText(hwndDlg,201,temp,6+1);
                           a=StrToU32(temp);
                           GetDlgItemText(hwndDlg,202,temp,3+1);
                           v=StrToU8(temp);

                           GetDlgItemText(hwndDlg,200,temp,256);
                           AddTheThing(hwndDlg,temp,a,v);
                          }
                          break;
								 case 1000:
									 CalculatorCheats (hwndDlg);
									 break;
                 case 106:
                        gornk:
//                        DestroyWindow(hwndDlg);
                        EndDialog(hwndDlg,0);
                        acwin=0;
                        break;
                }
              }
  return 0;
}

void ConfigAddCheat(HWND wnd)
{
 DialogBox(gui_hInstance,"ADDCHEAT",wnd,AddCheatCallB);
 #ifdef MOO
 if(!acwin)
  CreateDialog(gui_hInstance,"ADDCHEAT",0,AddCheatCallB);
 else
  SetFocus(acwin);
 #endif
}

#ifdef MOO
void UpdateCheatie(void)
{
 if(acwin)
 {
  int t;
  t=SendDlgItemMessage(acwin,101,LB_GETCURSEL,0,0);
  SendDlgItemMessage(acwin,108,LB_RESETCONTENT,0,0);
  CheatSearchGetRange(scrollindex+32768,scrollindex+32768+15,cfcallb);
  SendDlgItemMessage(acwin,101,LB_SETCURSEL,0,t);
 }
}
#endif